home *** CD-ROM | disk | FTP | other *** search
- /*
-
- Nullsoft WASABI Source File License
-
- Copyright 1999-2001 Nullsoft, Inc.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-
-
- Brennan Underwood
- brennan@nullsoft.com
-
- */
-
- // ===========================================================================
- //
- // NULLSOFT WASABI SDK EXAMPLE PROJECTS
- //
- // File: ExampleBWnd.cpp
- //
- //!## Purpose: This is the source module that contains the top-level
- //!## methods we'll be using for the construction of the ExampleB
- //!## window object.
- //
- // Requires: Please read ExampleBWnd.h first.
- //
- // Notes: A note on the comments in this document:
- // Notes that begin with *** are important notes that everyone
- // needs to read. The other comments assist readability or
- // explain the thinking behind sections of code which may not
- // be immediately obvious to the novice programmer.
- //
- // Or I'm just typing to hear myself clickyclack.
- //
-
- // Always begin with including std.h
- #include "../common/std.h"
-
- #include "ExampleB.h"
- #include "ExampleBwnd.h"
-
- // To be able to have Example1 as a Child Window
- #include "../example1/Example1Wnd.h"
- // Child Window Notification Messages
- #include "../common/notifmsg.h"
- // Core Handle for control of mp3 playback.
- #include "../common/corehandle.h"
- // Header to allow us to throw a textbar in there.
- #include "../common/textbar.h"
- // Header for generic guid mangling.
- #include "../common/nsguid.h"
- // Header for the _ object for language translation.
- #include "../common/xlatstr.h"
- // Header for ContWnd
- #include "../common/contwnd.h"
-
-
- // Oh, buttons get included up in there somewhere, too....
-
-
- // ===========================================================================
- //
- // EXAMPLEB: Static Globals
- //
-
- // A simple little static to help us lay out buttons, etc.
- static inline int PostIncReturn(int &counter, int amount)
- {
- // Return the given counter value and increment it by ``amount''
- int retval = counter;
- counter += amount;
- return retval;
- }
-
- // ===========================================================================
- //
- // EXAMPLEB: "ExampleBWnd::ExampleBWnd"
- //
- // *** We commit the tasks of 1) Instantiation and
- // 2) Assembly in the CONSTRUCTOR of the containment
- // class. The third primary task to occur before
- // normal framelooped behaviour, Initialization,
- // occurs AUTOMATICALLY for ALL contained objects by
- // the default baseclass onInit() event handler.
- //
- // *** In addition, it is important to note that any GUI
- // objects that take pointers to other gui objects have
- // the responsibility for deleting their interred pointrs
- // upon the destruction of that object.
- //
- ExampleBWnd::ExampleBWnd( void ) :
- myXMLURLBuffer() // Let our string member fully construct.
- {
- // Blah blah blah... default initialization values... yadda yadda yadda
- myUrlGrab = NULL;
- myDownloadState = EXB_DOWNLOAD_READY;
-
- //
- // In order to logically segregate the functions, we're
- // going to make a new method for our control class that
- // we call "createChildWindows" -- here's where we'll setup the
- // user interface objects that will exist in our sandbox.
- //
- // (This lets me move that whole block of code around if I
- // screw up and put it in the wrong place, or the API changes)
- int myRetval = createChildWindows();
- // and yes, we ignore the return code from the fxn.
- // what are you going to do about it, in a constructor?
- }
-
- // ===========================================================================
- //
- // EXAMPLEB: "ExampleBWnd::onInit()"
- //
- // So, okay, the setting of a timer falls neatly under the heading of
- // "initialization activities." This is how we latch our initialization
- // event and perform our method overrides. STANDARD C++ procedure, of
- // course, but I'm gonna be explicit about it, just so there's no problems:
- int ExampleBWnd::onInit() {
- // By calling our parent class' onInit method, we aught to have all
- // of our children properly initialized as well.
- int retval = EXAMPLEBWND_PARENT::onInit();
-
- setTimer(EXB_TIMER_ID, EXB_TIMER_DUR);
- return retval;
- }
-
- // ===========================================================================
- //
- // EXAMPLEB: "ExampleBWnd::timerCallback(int id)"
- //
- void ExampleBWnd::timerCallback(int id)
- {
- // Anyhow, so, we test the ID here to make sure we know
- // which timer fell out. Since we only have one timer,
- // we didn't HAVE to switch on it, but it helps to setup
- // your frameworks like this anyhow. Multiple if-chains
- // make things hard to read.
- switch (id)
- {
- case EXB_TIMER_ID:
- // Periodically, handle URL downloading.
- pollDownloadState();
- break;
-
- default:
- // If, by some vague stretch of our crazed imaginations,
- // someone ELSE in our window derivation chain decided to
- // send up a timer, we must then pass it along up the chain.
- EXAMPLEBWND_PARENT::timerCallback(id);
- // NO, DO NOT QUESTION, JUST DO IT. DO IT! DO IT NOW!!!
- //
- // grr!
- //
- break;
- };
-
- }
-
- // ===========================================================================
- //
- // EXAMPLEB: "ExampleBWnd::createChildWindows"
- //
- int ExampleBWnd::createChildWindows( void )
- {
- // So? What shall we do today?
-
- // Well, we're inherited from a tabsheet. That means we can make lots of
- // little children windows that do their own thing, create them here, add
- // them into ourselves, and then have them be properly initialized and
- // functional automatically by the system.
- //
- // Slikschiznitz, eh?
-
- // SO OKAY, now that we know that we are a tabsheet, I guess we start
- // stuffing kiddie windows into everything.
-
- // First we'll use the custom-blitting window code we created in Example1. That's
- // a good way to start. So, follow along here:
-
- // *** For a child of a tabsheet, the name of the window becomes the name
- // listed on the tab. So, the instructions here are:
- //
- // 1) Instantiate your child window object.
- Example1Wnd *myExample1Wnd = new Example1Wnd();
- // 2) Give it a name (altho you might have your own custom window
- // give itself its own name). For Tabsheet objects, the name
- // of the child object becomes the name in the tag.
- myExample1Wnd->setName(_("Boring"));
- // 3) Add it as a simple child to yourself.
- // NOTE: The "Add Child" method for TabSheet allows the specification
- // of a "TIP" string.
- addChild(myExample1Wnd,_("This is a boring version of ``hello world''"));
- // WIP: AFAICT, the tip string is currently ignored. But that won't crush
- // us, and it won't stop us from hoping that, one day, all the tip strings
- // in all the world can stand together hand in hand in the light of day without
- // fear of hatred or reprisals or silly little api bugs that prevent them
- // from attaining their full and complete and proper place in our society.
-
- //
- // *** Note the _("...") object. The _ object will feed your const string
- // through the localization and translation code to allow your strings
- // to be translated to other languages.
-
- //
- // Here's another copy of the blitter window, in a second tab.
- Example1Wnd *myExample1Wnd2 = new Example1Wnd( Example1Wnd::EXCITING );
- myExample1Wnd2->setName(_("Exciting"));
- addChild(myExample1Wnd2,_("This is a fun version of ``hello world''"));
-
- //
- // Now what we're going to do is have an individual method for the instantiation
- // and assembly of each tabsheet window. First up will be the example sheet to
- // display the proper care and feeding of a gaggle of buttons whose button
- // functionality is tied to the core MP3 functionality:
- createCoreButtonsSheet();
-
- //
- // This one will let you punch in an url to an XML sheet that will download and
- // display in a frame window assembly.
- createFramesSheet();
-
-
- // Until we clear up the little retval issue around here (possibly in a later
- // version of the SDK), return "0" for failure and "1" for success.
- return 1;
- }
-
- // ===========================================================================
- //
- // EXAMPLEB: "ExampleBWnd::createCoreButtonsSheet"
- //
- int ExampleBWnd::createCoreButtonsSheet() {
- // Make some fun buttons that link to the core controls.
-
- // First thing we do is make a container to hold our buttons.
- ContWnd * myButtonContainer = new ContWnd();
- // Name him, for the tab.
- myButtonContainer->setName(_("Buttons"));
- // Add him to ourselves to make a new tab sheet.
- addChild( myButtonContainer, _("This contains buttons that control core playback.") );
-
- //
- // *** Some things to know about ContWnd:
- //
- // ContWnd is made to contain objects with fixed sizes in a fixed layout.
- // The addChild() method explicitly defines and sets the rectangular size
- // of the children being added.
- //
-
- //
- // Now we start making the children objects for the button container.
- //
-
- // First thing we want to do is make up an inline counting system
- // to allow us to more easily lay out our buttons. The static inline
- // method used here is defined at the top of the module.
- int y = EXB_TOP_OFFSET; // used by PostIncReturn
- // By creating this, I can be lazy and cut and paste my buttons without
- // worrying about re-twiddling every pixel position by hand.
-
- // A play button would be nice. So we make a button.
- ButtonWnd *play = new ButtonWnd();
- // Then we give it some text to display.
- play->setButtonText("Play", 16);
- // And assign a notification ID to it.
- play->setButtonId(EXB_PLAY);
- // And assign our object to handle all notifications from this button
- play->setNotifyWindow(this);
- // And finally add it to the container window.
- myButtonContainer->addChild(play, EXB_LEFT_OFFSET,
- PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
- EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize*/);
-
- //
- // NOTE: The "Notify" stuff is where it all happens, but it's mildly complex.
- // checkout ExampleBWnd::childNotify() for where the magic happens.
- //
-
- // How about a stop button?
- ButtonWnd *stop = new ButtonWnd();
- stop->setButtonText(_("Stop"), 16);
- stop->setButtonId(EXB_STOP);
- stop->setNotifyWindow(this);
- myButtonContainer->addChild(stop, EXB_LEFT_OFFSET,
- PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
- EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
-
-
- // How about a pause button?
- ButtonWnd *pause = new ButtonWnd();
- pause->setButtonText(_("Pause"), 16);
- pause->setButtonId(EXB_PAUSE);
- pause->setNotifyWindow(this);
- myButtonContainer->addChild(pause, EXB_LEFT_OFFSET,
- PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
- EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
-
- // Space down by 2 yspacers.
- PostIncReturn(y, EXB_BUTTON_SPACER + EXB_BUTTON_SPACER);
-
- // "Previous" button....
- ButtonWnd *prev = new ButtonWnd();
- prev->setButtonText(_("Previous"), 16);
- prev->setButtonId(EXB_PREVIOUS);
- prev->setNotifyWindow(this);
- myButtonContainer->addChild(prev, EXB_LEFT_OFFSET,
- PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
- EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
-
- // "Next" button....
- ButtonWnd *next = new ButtonWnd();
- next->setButtonText(_("Next"), 16);
- next->setButtonId(EXB_NEXT);
- next->setNotifyWindow(this);
- myButtonContainer->addChild(next, EXB_LEFT_OFFSET,
- PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
- EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
-
- // Space down by 4 yspacers.
- PostIncReturn(y, EXB_BUTTON_SPACER * 4);
-
- // And create some text items.
- TextBar *textbar = new TextBar();
- textbar->setName(_("This is my text bar to say that the next text bars are my guid."));
- myButtonContainer->addChild(textbar, EXB_LEFT_OFFSET,
- PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
- EXB_BUTTON_WIDTH * 6, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
-
- // Want to display your GUID?
- TextBar *guidbar = new TextBar();
- char text[200];
- // I'm being a dick and connecting to my guid as a global variable.
- // that's lame and sloppy programming, kids. never do that. :)
- extern GUID exb_guid;
- guidbar->setName(nsGUID::toChar(exb_guid, text));
- // Oh yah, and DON'T be a goddamn hypocrite, either!
- // (inspect the "nsGUID::toChar" function, however)
- myButtonContainer->addChild(guidbar, EXB_LEFT_OFFSET,
- PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
- EXB_BUTTON_WIDTH * 6, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
-
- // Want to test that guids are being properly translated?
- GUID testGUID = nsGUID::fromChar(text);
-
- // Want to display your crosstranslated GUID?
- TextBar *testguidbar = new TextBar();
- char testtext[200];
- testguidbar->setName(nsGUID::toChar(testGUID, testtext));
- myButtonContainer->addChild(testguidbar, EXB_LEFT_OFFSET,
- PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
- EXB_BUTTON_WIDTH * 6, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
-
- // And one more text item for good measure, eh?
- TextBar *textbar2 = new TextBar();
- textbar2->setName(_("Are they equal?"));
- myButtonContainer->addChild(textbar2, EXB_LEFT_OFFSET,
- PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
- EXB_BUTTON_WIDTH * 6, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
-
-
- // For the nonce, return codes from and to the API should
- // return "0" for failure and "1" for success.
- return 1;
- }
-
- // ===========================================================================
- //
- // EXAMPLEB: "ExampleBWnd::childNotify"
- //
-
- //
- // Okay, so, we're going to use our single derived object to properly dispatch
- // all the messaging from our children of myriad diversity.
- //
- // This means I need to tell you about all the useful notification
- // messages that you might encounter in your day to day life with
- // our lovely little SDK:
- //
- // *** BUTTON Notifications:
- //
- // SO, firstly, we have buttons. Stock ButtonWnd objects will send the
- // following Notification messages:
- //
- // CHILD_NOTIFY_LEFTPUSH
- // CHILD_NOTIFY_RIGHTPUSH
- // CHILD_NOTIFY_LEFTDOUBLECLICK
- // CHILD_NOTIFY_RIGHTDOUBLECLICK
- //
- // And the id that you assign to the button is sent as param1.
- //
- int ExampleBWnd::childNotify (RootWnd *which, int msg, int param1, int param2) {
-
- # if 1 // WIP
-
- char text[200];
- wsprintf(text,"Incoming rootWnd-childNotify: ptr:0x%08X msg:0x%03X p1:0x%08X p2:0x%08X \n",
- which, msg, param1, param2);
- OutputDebugString(text);
-
- # endif // WIP
-
- //
- // For the nonce, we're going to ignore the pointer to the object who is
- // sending the notification event. Pointers are icky, smelly, and if you
- // touch them, you'll have to wash your hands with an aerosol oven cleaner
- // for a week just to make sure you're not accidentally besmirched.
- //
- // OBVIOUSLY, if any of the objects you're using require an acknowledgement
- // or any other method to be called on them, you'll want to implement a
- // schema for your code that keeps the "which" pointer around. But we're
- // not going to bother being that complicated here, kiddies.
- //
- // Uncle mig's got a deadline, you know.
- //
- handleChildNotify(msg, param1, param2);
-
- return EXAMPLEBWND_PARENT::childNotify(which, msg, param1, param2);
- }
-
-
- // ===========================================================================
- //
- // EXAMPLEB: "ExampleBWnd::handleChildNotify"
- //
- // Just to show off message handling without pointers.
- //
- int ExampleBWnd::handleChildNotify (int msg, int param1, int param2) {
- //
- // We're all familiar with nested switch for event handling.
- // There's nothing scary to be seen, here.
- switch(msg)
- {
- // Messages from our buttons being pushed.
- case CHILD_NOTIFY_LEFTPUSH :
- case CHILD_NOTIFY_RIGHTPUSH :
- case CHILD_NOTIFY_LEFTDOUBLECLICK :
- case CHILD_NOTIFY_RIGHTDOUBLECLICK :
- {
- //
- // So, now, what we're going to do here is if ANY of those
- // messages came in, we just check which object ID shot that
- // message out in order to know what to do with it.
- //
- int ButtonID = param1; // Just a clarification assignment.
- // Switch on the ID to call the core handle.
- switch(ButtonID)
- {
- case EXB_PREVIOUS:
- {
- OutputDebugString(_("Button pushed corresponds to EXB_PREVIOUS ButtonID\n"));
- CoreHandle newHandle;
- newHandle.prev();
- break;
- }
-
- case EXB_PLAY:
- {
- OutputDebugString(_("Button pushed corresponds to EXB_PLAY ButtonID\n"));
- CoreHandle newHandle;
- newHandle.play();
- break;
- }
-
- case EXB_PAUSE:
- {
- OutputDebugString(_("Button pushed corresponds to EXB_PAUSE ButtonID\n"));
- CoreHandle newHandle;
- newHandle.pause();
- break;
- }
-
- case EXB_STOP:
- {
- OutputDebugString(_("Button pushed corresponds to EXB_STOP ButtonID\n"));
- CoreHandle newHandle;
- newHandle.stop();
- break;
- }
-
- case EXB_NEXT:
- {
- OutputDebugString(_("Button pushed corresponds to EXB_NEXT ButtonID\n"));
- CoreHandle newHandle;
- newHandle.next();
- break;
- }
-
- // Ah! THIS button is created and used on the "Frames" sheet, in the other module.
- case EXB_XML_GO:
- {
- OutputDebugString(_("Button pushed corresponds to EXB_XML_GO ButtonID\n"));
- // And you'll find this method there, as well.
- startURLDownload();
- break;
- }
-
- default:
- // Hrrmph.
- return 0;
- }
- }
- break;
-
- default:
- // Hrrmph.
- return 0;
- }
-
- //
- // Yawn. Do I care about my error condition, here?
- //
- // Oh PROBABLY.
- //
- // SOMEWHERE.
- //
- // Maybe in North Dakota or something.
- //
- // So, if you're a developer, and you're IN North Dakota, well,
- // I feel so sorry for you that I'd suggest immediately changing
- // the return value here from a 1 to a 0. It won't make a big
- // difference in the functionality here, but it will help bring
- // unto you that most invaluable of gifts:
- //
- // Peace of mind.
- //
- // See, aren't I a great pal?
- return 1;
- }
-